Chanquo2系
概要
Chanquo = Typeを接続用パラメータとして扱うGoのchannelもどき for Unity。
1系は正直適当な実装だったんで、goのコードを読みながらアップグレードを目論む。
互換性は破壊されちゃったらごめんねみたいな想定。->破壊されました。やったぜ!
1系のダメなところ
・structを使えない(致命傷)
・マルチレシーブが特に必要ない感じ(タイムアウトとかがつけば別だが、それはそれで変な実装になる。
・yield returnしたい(一件受けたら云々とか)
・スロットルの概念があってもいい(N個をまとめて受ける)
・MainThreadDispatcher頼み(シーンを超えられるが、超えていいケースは少なかった。)
・コードが汚い(美しくない、拡張性が低い)
・Jobまわりを綺麗にアレしたいができない
ということで、2系の開発に取り組み、完成した。
Chanquo
https://github.com/sassembla/Chanquo
対応し途中のもの
・スロットルの概念があってもいい(N個をまとめて受ける)
・Jobまわりを綺麗にアレしたいができない
これらは途中。で、これら以外は対応できた。
結果
こんな感じの書き方ができるようになった。
var ch = Chan<T>.Make();
ch.Send(new T(){});
struct型Tを指定して、chの生成、chへとデータの送付。
goでの ch <- データ みたいな形。
受け取り側は複数パターンが使えて、
// start receiving data asynchronously.
ch.Receive(
(T data, bool ok) => {
// ok will become false when the channel is closed somewhere.
// when ok is false, data is empty.
}
);
1. select 文に対するcase data, ok := <- chのような扱い。
非同期で継続的な受け取り。これはv1と同じようなシグニチャになっている。と思ったけどそうでもないか。
誰かがchをCloseするとokがfalseな状態で飛んでくる。
// receive data until Chan<T> is closed.
yield return Channels.For<T>(
T t =>
{
}
);
2. こちらはfor文での for data := range ch 相当。
Unityの場合はブロックせずに一定の位置で待つ、というのがasync汚染なしでは辛い(なんかいい手段ある?)という感じなので、
yield return と組み合わせる形にしている。
// wait first data then go through.
yield return Channels.WaitFirst<T>();
3. こちらは単純に <- ch と同じようなもの。
T型のデータがどこかから送信されると、yieldを抜ける。
goの場合はgoroutineでブロックをつくりまくっても全体には影響が及ばないのだが、
Unity C#の場合はブロックするとてきめんに詰む。
そのため、「その位置で待つ」という機能としてyield returnを使っている。
感想
より捨てやすく、なんとなーくUnityフレンドリーな書き方もできるようになった。
structが使えるのもよい。